package com.siwei.mes.service.materials.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.siwei.mes.common.query.PageQuery;
import com.siwei.mes.common.util.ConvertUtils;
import com.siwei.mes.entity.ShxhSynchronizedata;
import com.siwei.mes.entity.UploadLaboratoryEntity;
import com.siwei.mes.entity.erp.Rwdextra;
import com.siwei.mes.entity.experiment.Experiment;
import com.siwei.mes.entity.materials.Materials;
import com.siwei.mes.entity.materials.MaterialsSpecConfig;
import com.siwei.mes.entity.mixproportion.MixProportion;
import com.siwei.mes.enums.ExperimentStatusEnum;
import com.siwei.mes.enums.MaterialsEnum;
import com.siwei.mes.mapper.ShxhSynchronizedataMapper;
import com.siwei.mes.mapper.experiment.ExperimentMapper;
import com.siwei.mes.mapper.materials.MaterialsMapper;
import com.siwei.mes.mapper.materials.MaterialsSpecConfigMapper;
import com.siwei.mes.mapper.materials.SupplierCompanyMaterialsMapper;
import com.siwei.mes.mapper.mixProportion.MixProportionMapper;
import com.siwei.mes.service.erp.RwdextraService;
import com.siwei.mes.service.laboratory.UploadAndDownloadAssociationService;
import com.siwei.mes.service.laboratory.UploadLaboratoryService;
import com.siwei.mes.service.materials.MaterialsService;
import com.siwei.mes.service.sync.erp.ErpProjectService;
import com.siwei.mes.sync.config.SyncProcessorService;
import com.siwei.mes.upload.erp.UploadErpService;
import com.siwei.mes.upload.erp.entity.ErpAddTaskPhbLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.siwei.mes.common.exception.handler.MessageHandler.assertTrue;

/**
 * 物料表(Materials)表服务实现类
 *
 * @author linzi
 * @since 2023-11-27 22:46:48
 */
@Slf4j
@Service
public class MaterialsServiceImpl implements MaterialsService {
    @Resource
    private MaterialsMapper materialsMapper;
    @Resource
    private MaterialsSpecConfigMapper materialsSpecConfigMapper;
    @Resource
    private ExperimentMapper experimentMapper;
    @Resource
    private SupplierCompanyMaterialsMapper supplierCompanyMaterialsMapper;
    @Resource
    private SyncProcessorService syncProcessorService;
    @Resource
    private ShxhSynchronizedataMapper shxhSynchronizedataMapper;
    @Resource
    private UploadAndDownloadAssociationService uploadAndDownloadAssociationService;
    @Resource
    private UploadLaboratoryService uploadLaboratoryService;

    @Resource
    private MixProportionMapper mixProportionMapper;
    @Resource
    private UploadErpService uploadErpService;
    @Resource
    private ErpProjectService erpProjectService;
    @Resource
    private RwdextraService rwdextraService;

    // 创建一个固定大小的线程池
    private final ExecutorService executorService = Executors.newFixedThreadPool(5);

    @Override
    public List<String> getMaterialsNameByType(Long materialType) {
        return materialsMapper.getMaterialsNameByType(materialType);
    }

    @Override
    public List<String> getMaterialsSpecs(String materialName, Long materialType) {
        return materialsMapper.getMaterialsSpecs(materialName, materialType);
    }

    @Override
    public void configSpecId(Materials entity) {
        Materials materials = materialsMapper.selectByPrimaryKey(entity.getId());
        assertTrue(materials == null, "物料信息不存在");
        MaterialsSpecConfig specConfig = materialsSpecConfigMapper.selectByPrimaryKey(entity.getSpecId());
        assertTrue(specConfig == null, "材料及规格配置信息不存在");

        entity.init(false);
        materialsMapper.updateByPrimaryKeySelective(entity);
        /**这里如果设置了 需要批量修改供应商物料对应的物料id*/
        supplierCompanyMaterialsMapper.updateSpecIdByMaterialsId(entity.getId(), entity.getSpecId());

        /**设置之后需要修改修改绑定了该物料的所有试验委托sampleLevle字段**/
        String sampleLevel = (StringUtils.isNotEmpty(specConfig.getMaterialAbbreviation()) ? specConfig.getMaterialAbbreviation() : specConfig.getMaterialsName()) + specConfig.getMaterialsSpec();


        Experiment experiment = new Experiment();
        experiment.setMaterialsId(String.valueOf(entity.getId()));
        /**这里只处理混凝土的  混凝土的只需要规格 C5-C100*/
        if (specConfig.getMaterialsType().equals(MaterialsEnum.CONCRETE.getCode())) {
            experiment.setSampleLevel(specConfig.getMaterialsSpec());
        } else {
            experiment.setSampleLevel(sampleLevel);
        }
        experiment.setMaterialsName(specConfig.getMaterialsName());
        experiment.setMaterialsSpecs(specConfig.getMaterialsSpec());
        experiment.setSpecId(entity.getSpecId());
        String abbreviation = specConfig.getMaterialAbbreviation();
        experiment.setMaterialAbbreviation(StringUtils.isBlank(abbreviation) ? specConfig.getMaterialsName() : abbreviation);
        /*新建委托数据应该在绑定物料时再修改对应
        experimentMapper.updateSampleLevelBySpecId(experiment);*/
        experimentMapper.updateSampleLevelByMaterialsId(experiment);

        // 提交任务到线程池
        executorService.submit(() -> {
            log.info("开始在线程中执行修改了对应物料的规格，开始推送试验委托信息到协会！");
            /**修改之后  给所有试验委托id推送给协会 重新上传*/
            List<Integer> experimentStatusList = new ArrayList<>();
            experimentStatusList.add(ExperimentStatusEnum.WAIT_ACCEPT.getCode());
            experimentStatusList.add(ExperimentStatusEnum.WAIT_SAMPLING.getCode());
            experimentStatusList.add(ExperimentStatusEnum.IN_TEST.getCode());
            List<Experiment> experimentList = experimentMapper.getList(new Experiment().setExperimentStatusList(experimentStatusList).setMaterialsId(String.valueOf(entity.getId())));
            for (Experiment experimentInfo : experimentList) {
                //查询是否上传
                List<ShxhSynchronizedata> list = shxhSynchronizedataMapper.getList(new ShxhSynchronizedata().setExperimentId(experimentInfo.getId()));
                if (list == null || list.isEmpty()) {
                    log.info("修改了对应物料的规格，为上传的则不处理，试验委托id：【{}】", experimentInfo.getId());
                    continue;
                }
                String experimentId = String.valueOf(experimentInfo.getId());
                log.info("修改了对应物料的规格，开始推送试验委托信息到协会，试验委托id：【{}】", experimentId);

                if (list.get(0) != null && StringUtils.isNotBlank(list.get(0).getSampleId())) {

                    if (MaterialsEnum.CONCRETE.getCode().equals(experimentInfo.getExperimentType())) {
                        uploadAndDownloadAssociationService.delDataDefaultUc(list.get(0).getSampleId());
                    } else {
                        //原材料 修改规格
                        uploadLaboratoryService.modifySpecifications(list.get(0).getSampleId(), experiment);
                    }

                    syncProcessorService.submitRequest(new UploadLaboratoryEntity().setExperimentId(Collections.singletonList(experimentId)).setUploadState(0));

                }


            }
        });
    }

    /**
     * 在 Bean 销毁时关闭线程池
     */
    @PreDestroy
    public void destroy() {
        executorService.shutdown();
        log.info("关闭修改了对应物料的规格，开始推送试验委托信息到协会线程池");
    }

    @Override
    public List<Materials> getAll(Materials entity) {
        return materialsMapper.getList(entity);
    }

    @Override
    public PageInfo<Materials> getPage(PageQuery<Materials, Materials> query) {
        Materials searchParam = query.getParams();
        return PageHelper.startPage(query.getPageNum(), query.getPageSize())
                .doSelectPageInfo(() -> materialsMapper.getList(searchParam));
    }

    @Override
    public Materials checkIsExist(Integer materialType, String materialName, String materialSpec) {
        if (StringUtils.isBlank(materialSpec)) {
            log.info("对应物料规格为空，不去操作物料基本配置表");
            return null;
        }
        Materials select = new Materials().setMaterialType(materialType).setMaterialName(materialName).setMaterialSpecs(materialSpec);
        List<Materials> materialsList = materialsMapper.select(select);
        Long materialsId = null;
        if (materialsList.isEmpty()) {
            select.setId(null).setCreateTime(new Date()).setUpdateTime(new Date());
            MaterialsEnum materialsEnum = MaterialsEnum.selectByCode(materialType);
            if (materialsEnum != null) {
                select.setMaterialTypeName(materialsEnum.getName());
            }
            int count = materialsMapper.insertSelective(select);
            materialsId = select.getId();
            if (count > 0) {
                materialsMapper.updateAllMaterialsNo();
            }
        } else {
            materialsId = materialsList.get(0).getId();
        }


        Materials materials = materialsMapper.loadById(materialsId);
        /**如果这里没有设置对应的规格设置*/
        if (materials.getSpecId() == null && materialType.equals(MaterialsEnum.CONCRETE.getCode())) {
            String mesTpz = ConvertUtils.getMesTpz(materialSpec);
            /**查询对应的材料是否有数据  如果有直接绑定  如果没有就跳过*/
            MaterialsSpecConfig specConfig = materialsSpecConfigMapper.getSpecConfigInfo(MaterialsEnum.CONCRETE.getCode(), MaterialsEnum.CONCRETE.getName(), mesTpz);
            log.info("开始查询对应材料及规格配置表信息，查询条件：materialType={}, materialName={}, materialSpec={}", MaterialsEnum.CONCRETE.getCode(), MaterialsEnum.CONCRETE.getName(), mesTpz);
            if (specConfig != null) {
                materials.setSpecId(specConfig.getId());
                materials.setUpdateTime(new Date());
                materialsMapper.updateByPrimaryKeySelective(materials);
            }
        }
        return materials;
    }

    @Override
    public void delete(Long id) {
        Materials materials = materialsMapper.selectByPrimaryKey(id);
        assertTrue(materials == null, "物料信息不存在");
        materialsMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Integer getMaterialsType(String materialName, String materialSpec) {
        return materialsMapper.getMaterialsType(materialName, materialSpec);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindPhbNo(Long id, String phbNo) {
        Materials materials = materialsMapper.loadById(id);
        assertTrue(materials == null, "物料信息不存在");
        assertTrue(!materials.getMaterialType().equals(MaterialsEnum.CONCRETE.getCode()), "只有物料类型是混凝土的才可以绑定配合比");

        //assertTrue(materials.getIsIronMark() == 0, "非铁标不能绑定配合比");

        MixProportion mixProportion = mixProportionMapper.selectByPhbNo(phbNo);
        assertTrue(mixProportion == null, "配合比信息不存在");

        if (mixProportion.getErpPhbId() == null) {
            log.info("绑定配合比未查询到erp配合比id，直接跳过！");
            return;
        }

        Materials updateInfo = new Materials();
        updateInfo.setId(id).setPhbNo(phbNo).setIsIronMark(0).init(false);
        materialsMapper.updateByPrimaryKeySelective(updateInfo);

        /**查询所有铁标工程名称*/
        List<String> projectNameList = erpProjectService.getIsIronMarkProjectName();

        if (projectNameList.isEmpty()) {
            log.info("绑定配合比未查询到铁标工程名称，直接跳过！");
            return;
        }

        /**这里直接查询任务单是这个工程的*/
        List<Rwdextra> rwdextraList = rwdextraService.selectIronMarkInfo(projectNameList, materials.getMaterialSpecs());
        if (rwdextraList.isEmpty()) {
            log.info("绑定配合比没有查询出任务单信息，直接跳过!  工程名称：{}， 物料规格：{}", projectNameList, materials.getMaterialSpecs());
            return;
        }
        List<String> taskIdList = new ArrayList<>();
        for (Rwdextra rwdextra : rwdextraList) {
            if (rwdextra.getFrwdh() == null) {
                continue;
            }
            taskIdList.add(String.valueOf(rwdextra.getFrwdh()));
        }

        /**推送到erp*/
        try {
            ErpAddTaskPhbLog erpAddTaskPhbLog = new ErpAddTaskPhbLog();
            erpAddTaskPhbLog.setTaskIds(String.join(",", taskIdList));
            erpAddTaskPhbLog.setPhbId(Integer.valueOf(mixProportion.getErpPhbId()));
            erpAddTaskPhbLog.setPhbNo(phbNo);
            uploadErpService.uploadAddTaskPhbLog(erpAddTaskPhbLog, false);
        } catch (Exception e) {
            log.info("组装推送到erp失败，失败原因：{}", e.getMessage());
        }
    }
}
